﻿//-----------------------------------------------------------------------
// <copyright file="ConcurrentResource.cs" author="Artak Mkrtchyan">
//     Creative Commons - GNU General Public License (http://creativecommons.org/licenses/GPL/2.0/
// </copyright>
// <author>Artak Mkrtchyan</author>
// <email>mkArtak@gmail.com</email>
// <date>30/07/2012</date>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleHoster.Common.Utilities.Threading
{
	public class ConcurrentResource<T>
	{
		private readonly Object SyncRoot = new Object();
		private T resource;
		private volatile bool isLocked = false;

		public ConcurrentResource(T argResource)
		{
			if (argResource == null)
			{
				throw new ArgumentNullException("argResource");
			}

			this.resource = argResource;
		}

		public void LockForAction(Action argAction)
		{
			new Action(() =>
				{
					this.RunActionSwitchingToLockedMode(argAction);
				}).SyncronizeCallByLocking(this.SyncRoot);
		}

		public void LockForActionWithPulse(Action argAction)
		{
			new Action(() =>
				{
					if (argAction != null)
					{
						this.RunActionSwitchingToLockedMode(argAction);
					}
					this.Pulse();
				}).SyncronizeCallByLocking(this.SyncRoot);
		}

		private void RunActionSwitchingToLockedMode(Action argAction)
		{
			this.isLocked = true;
			argAction();
			this.isLocked = false;
		}

		public void Pulse()
		{
			Monitor.PulseAll(this.SyncRoot);
		}

		public void Wait()
		{
			Monitor.Wait(this.SyncRoot);
		}

		public void ReleaseAnyWaitingThreads()
		{
			this.LockForActionWithPulse(null);
		}

		public T Resource
		{
			get
			{
				return this.resource;
			}
			set
			{
				if (this.isLocked == false)
				{
					throw new ConcurrentResourceAccessException();
				}
				this.resource = value;
			}
		}
	}
}
